﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using BoolanElement.UI.Table;
using BoolanSlide.RedoUndo;
using BoolanSlide.UIElement.Table.Operation;
using BoolanSlide.UIElement.Table.Operation.Create;
using BoolanSlide.UIElement.Table.Structure.Element;
using Windows.Data.Xml.Dom;
using Windows.UI.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace BoolanElement
{
    public class BooTableElement:BooElement,INotifyPropertyChanged
    {
        public BooTableData Data;
        public BooTableStyle Style;
        public List<List<BooTableElementUnit>> Units;
        public int RowCount;
        public int ColumnCount;

        public event PropertyChangedEventHandler PropertyChanged;
        public event TablePropertyChangedHandler TablePropertyChanged;

        public new double Width 
        {
            set 
            {
                ElementTransform.Width = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Width"));
            }
            get
            {
                return ElementTransform.Width;
            }
        }

        public new double Height
        {
            set
            {
                ElementTransform.Height = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Height"));
            }
            get
            {
                return ElementTransform.Height;
            }
        }

        public SolidColorBrush BorderBrush
        {
            set 
            {
                Style.borderStyle.BorderColor = value.Color;
                TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
                arg.Operation = TablePropertyChangedArgs.ChangeProperty;
                arg.PropertyName = "BorderBrush";
                TablePropertyChanged(this, arg);
            }
            get 
            {
                return new SolidColorBrush(Style.borderStyle.BorderColor);
            }
        }

        public int BorderThickness
        {
            set
            {
                Style.borderStyle.BorderThickness = value;
                TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
                arg.Operation = TablePropertyChangedArgs.ChangeProperty;
                arg.PropertyName = "BorderThickness";
                arg.NeedToSaveForRedoUndo = false;
                TablePropertyChanged(this, arg);
            }
            get
            {
                return Style.borderStyle.BorderThickness;
            }
        }

        public void SetBorderThickness(int borderThickness, bool NeedToSaveForRedoUndo)
        {
            Style.borderStyle.BorderThickness = borderThickness;
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.ChangeProperty;
            arg.PropertyName = "BorderThickness";
            arg.NeedToSaveForRedoUndo = NeedToSaveForRedoUndo;
            TablePropertyChanged(this, arg);
        }

        public BooTableElement()
        {
            RowCount = 0;
            ColumnCount = 0;
            Units = new List<List<BooTableElementUnit>>();
            Data = new BooTableData(this);
            Style = new BooTableStyle(this);
        }

        public BooTableElementUnit GetUnit(int row, int column)
        {
            return Units.ElementAt(row).ElementAt(column);
        }

        public String GetData(int row, int column)
        {
            return Data.GetData(row,column);
        }

        public void SetDataDocument(int row, int column,RichEditBox box)
        {
            Data.SetDataDocument(row, column,box);
        }

        public void SetData(string content,int row, int column)
        {
            Data.SetData(new BooTableDataUnit(content),row,column);
        }

        public void SetData(ITextDocument content, int row, int column)
        {
            Data.SetData(new BooTableDataUnit(content), row, column);
        }

        public void SetRowData(int row, List<BooTableElementUnit> rowData)
        {
            if (rowData == null)
                return;
            int count = Units.ElementAt(row).Count > rowData.Count ? rowData.Count : Units.ElementAt(row).Count;
            for (int i = 0; i < count; ++i)
            {
                Units.ElementAt(row)[i].Load(rowData.ElementAt(i));
            }
        }

        public void SetColumnData(int column, List<BooTableElementUnit> columnData)
        {
            if (columnData == null)
                return;
            int count = Units.Count > columnData.Count ? columnData.Count : Units.Count;
            for (int i = 0; i < count; ++i)
            {
                Units.ElementAt(i).ElementAt(column).Load(columnData.ElementAt(i));
            }
        }

        public List<BooTableElementUnit> GetRowData(int row)
        {
            List<BooTableElementUnit> units = new List<BooTableElementUnit>();
            foreach (var item in Units.ElementAt(row))
            {
                units.Add(item);
            }
            return units;
        }

        public List<BooTableElementUnit> GetColumnData(int row)
        {
            List<BooTableElementUnit> ret = new List<BooTableElementUnit>();
            foreach (var rowdata in Units)
            {
                ret.Add(rowdata.ElementAt(row));
            }
            return ret;
        }

        public void Resize(int rowCount, int columnCount)
        {
            this.RowCount = rowCount; 
            this.ColumnCount = columnCount;
            Units.Clear();
            for (int row = 0; row < rowCount; ++row)
            {
                List<BooTableElementUnit> rowData = new List<BooTableElementUnit>(columnCount);
                for (int j = 0; j < columnCount; ++j)
                {
                    BooTableElementUnit unit = new BooTableElementUnit(row,j);
                    rowData.Add(unit);
                }
                Units.Add(rowData);
            }
        }

        public void AddRow(int row)
        {
            if (RowCount >= 100)
                return;
            RowCount++;
            List<BooTableElementUnit> refRow = Units.ElementAt(row);
            List<BooTableElementUnit> rowData = new List<BooTableElementUnit>(ColumnCount);
            for (int j = 0; j < ColumnCount; ++j)
            {
                rowData.Add(new BooTableElementUnit(refRow.ElementAt(j)));
            }
            Units.Insert(row, rowData);
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.AddRow;
            arg.EffectRow = row;
            TablePropertyChanged(this, arg);
        }

        public void AddRowAtEnd()
        {
            if (RowCount >= 100)
                return;
            RowCount++;
            List<BooTableElementUnit> lastRow = Units.Last();
            List<BooTableElementUnit> rowData = new List<BooTableElementUnit>(ColumnCount);
            for (int j = 0; j < ColumnCount; ++j)
            {
                rowData.Add(new BooTableElementUnit(lastRow[j]));
            }
            Units.Add(rowData);
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.AddRowAtEnd;
            TablePropertyChanged(this, arg);
        }

        public void AddColumn(int column)
        {
            if (ColumnCount >= 100)
                return;
            ColumnCount++;
            foreach (List<BooTableElementUnit> rowData in Units)
            {
                rowData.Insert(column, new BooTableElementUnit(rowData.ElementAt(column)));
            }
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.AddColumn;
            arg.EffectColumn = column;
            TablePropertyChanged(this, arg);
        }

        public void AddColumnAtEnd()
        {
            if (ColumnCount >= 100)
                return;
            ColumnCount++;
            foreach (List<BooTableElementUnit> rowData in Units)
            {
                rowData.Add(new BooTableElementUnit(rowData.Last()));
            }
            TablePropertyChangedArgs arg=new TablePropertyChangedArgs();
            arg.Operation=TablePropertyChangedArgs.AddColumnAtEnd;
            TablePropertyChanged(this, arg);
        }

        public void DeleteRow(int row)
        {
            if (RowCount <= 1)
                return;
            RowCount--;
            Units.RemoveAt(row);
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.DeleteRow;
            arg.EffectRow = row;
            TablePropertyChanged(this, arg);
        }

        public void DeleteColumn(int column)
        {
            if (ColumnCount <= 1)
                return;
            ColumnCount--;
            foreach (List<BooTableElementUnit> rowData in Units)
            {
                rowData.RemoveAt(column);
            }
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.DeleteColumn;
            arg.EffectColumn = column;
            TablePropertyChanged(this, arg);
        }

        public void ResizeRow(int effectRow, double newHeight)
        {
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.ResizeRow;
            arg.EffectRow = effectRow;
            arg.deltaValue = newHeight;
            TablePropertyChanged(this, arg);
        }
        public void ResizeColumn(int effectColumn, double newWidth)
        {
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.ResizeColumn;
            arg.EffectColumn = effectColumn;
            arg.deltaValue = newWidth;
            TablePropertyChanged(this, arg);
        }

        public void ResizeAllRow(double deltaValue, int direction)
        {
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.ResizeAllRow;
            arg.deltaValue = deltaValue;
            arg.direction = direction;
            TablePropertyChanged(this, arg);
        }
        public void ResizeAllColumn(double deltaValue, int direction)
        {
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.ResizeAllColumn;
            arg.deltaValue = deltaValue;
            arg.direction = direction;
            TablePropertyChanged(this, arg);
        }

        public void UpdateUI(BooTableElement element)
        {
            TablePropertyChangedArgs arg = new TablePropertyChangedArgs();
            arg.Operation = TablePropertyChangedArgs.UpdateUI;
            arg.Data = element;
            TablePropertyChanged(this, arg);
        }

        /// <summary>
        /// 元件呈现
        /// </summary>
        public override async Task<BooUIBase> Render(SaveOriginalElement saveOriginal, SaveForRedoUndo saveForRedoUndo)
        {
            BooTable table = new BooTable(this, saveForRedoUndo);
            RedoUndoHelper.SaveOriginalStatus(table);
            TableCreateHelper.LoadFromElement(table);
            return table;
        }
        public override async Task<BooUIBase> RenderForThumbNails()
        {
            BooTable table = new BooTable(this);
            TableCreateHelper.LoadFromElement(table);
            return table;
        }


        public override XElement SaveToXElement()
        {
            XElement element=new XElement(typeof(BooTableElement).Name);

            element.SetAttributeValue("Row", RowCount.ToString());
            element.SetAttributeValue("Column", ColumnCount.ToString());
            element.SetAttributeValue("UniqueID", UniqueID.ToString());

            element.Add(ElementTransform.Save());
            element.Add(Data.Save(this));
            element.Add(Style.Save());
            return element;
        }

        public override void LoadFromXElement(XElement element)
        {
            RowCount = Convert.ToInt32(element.Attribute("Row").Value);
            ColumnCount = Convert.ToInt32(element.Attribute("Column").Value);
            UniqueID = Convert.ToInt32(element.Attribute("UniqueID").Value);

            this.Resize(RowCount, ColumnCount);

            ElementTransform.Load(element.Element("Transform"));
            Data.Load(this,element.Element("Data"));
            Style.Load(element.Element("Style"));
        }

        public void Reset()
        {
            Style = new BooTableStyle(this);
            Data = new BooTableData(this);
        }

        public override BooElement Clone()
        {
            BooTableElement element= (BooTableElement)this.MemberwiseClone();
            element.PropertyChanged = null;
            element.TablePropertyChanged = null;
            element.ElementTransform = ElementTransform.Clone();

            element.Units = new List<List<BooTableElementUnit>>();
            for (int i = 0; i < Units.Count; ++i)
            {
                element.Units.Add(new List<BooTableElementUnit>());
                for (int j = 0; j < Units.ElementAt(i).Count; ++j)
                {
                    BooTableElementUnit unit = Units.ElementAt(i).ElementAt(j);
                    element.Units.ElementAt(i).Add(unit.Clone());
                }
            }
            element.Reset();
            element.Style.borderStyle.BorderColor = this.Style.borderStyle.BorderColor;
            element.Style.borderStyle.BorderThickness = this.Style.borderStyle.BorderThickness;
            return element;
        }

        public void Load(BooTableElement element)
        {
            this.RowCount = element.RowCount;
            this.ColumnCount = element.ColumnCount;
            this.ElementTransform = element.ElementTransform;
            this.Units = element.Units;
            this.Reset();
            this.Style.borderStyle.BorderColor = element.Style.borderStyle.BorderColor;
            this.Style.borderStyle.BorderThickness = element.Style.borderStyle.BorderThickness;
        }

        /// <summary>
        /// 一般用于测试输出
        /// </summary>
        /// <returns></returns>
        public override String ToString()
        {
            return "";
        }
    }
}
